Skip to content

[configure] Configure Kubelet Log Level Verbosity#147

Open
jing2uo wants to merge 2 commits intomainfrom
kb/2026-04-21/configure-kubelet-log-level-verbosity
Open

[configure] Configure Kubelet Log Level Verbosity#147
jing2uo wants to merge 2 commits intomainfrom
kb/2026-04-21/configure-kubelet-log-level-verbosity

Conversation

@jing2uo
Copy link
Copy Markdown
Collaborator

@jing2uo jing2uo commented Apr 22, 2026

新增一篇 ACP KB 文章,归入 configure 区域。

✅ 自动化验证通过 — 2 / 2 条验证步骤在真实 Kubernetes 集群上按文章命令跑通(2026-04-22T13:12:03Z)。

configure 区域建议 reviewer

kb/OWNERS.md + kb/KB_REVIEWERS.md 该区域的活跃人自动挑选,@ 错了请无视。

@changluyi @zhangzujian @oilbeater

没有 GitHub handle 的贡献者(本区域相关请人工 ping):

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Walkthrough

Added new troubleshooting documentation explaining how to increase kubelet log verbosity for diagnosing node-level issues. The guide covers supported verbosity ranges (0–10), configuration procedures for kubeadm-based clusters, systemd drop-in methods, immutable-OS nodes, and verification steps via kubectl debug and journalctl.

Changes

Cohort / File(s) Summary
Kubelet Troubleshooting Documentation
docs/en/solutions/Configure_Kubelet_Log_Level_Verbosity.md
New troubleshooting guide detailing kubelet log level verbosity configuration across multiple environments, including kubeadm-based persistent config, systemd drop-in fallbacks, immutable-OS infrastructure patterns, and diagnostic commands for verification and log collection.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Poem

🐰 Hop along, dear admin friends,
When kubelet's whispers never end,
With -v=4 we raise the call,
And verbosity shall tell us all!
From kubeadm to systemd's grace,
We troubleshoot at every place. 🔍

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[configure] Configure Kubelet Log Level Verbosity' directly aligns with the main change: adding documentation for configuring kubelet log verbosity in the configure area.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kb/2026-04-21/configure-kubelet-log-level-verbosity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jing2uo jing2uo requested a review from oilbeater April 22, 2026 07:08
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/en/solutions/Configure_Kubelet_Log_Level_Verbosity.md`:
- Around line 126-128: The loop uses node names (variable n and ssh "$n") which
may not be DNS-resolvable; change the selection to use each node's InternalIP
and keep the node name for filenames: iterate over pairs (node name and
InternalIP) by replacing the kubectl invocation with a jsonpath or
custom-columns query (e.g., kubectl get nodes -o jsonpath='{range
.items[*]}{.metadata.name}
{.status.addresses[?(@.type=="InternalIP")].address}{"\n"}{end}' or equivalent),
then in the loop use ssh "$IP" to run sudo journalctl -u kubelet.service --since
'1 hour ago' and redirect to "${NODE}.kubelet.log" so SSH targets the reachable
IP while filenames still use the node name.
- Line 43: Update the paragraph to correct the factual error: state that the
kubeadm systemd unit template expands four variables in ExecStart —
$KUBELET_KUBECONFIG_ARGS, $KUBELET_CONFIG_ARGS, $KUBELET_KUBEADM_ARGS, and
$KUBELET_EXTRA_ARGS — and remove the claim that KUBELET_EXTRA_ARGS is "silently
ignored"; instead note that KUBELET_EXTRA_ARGS (sourced from
/etc/default/kubelet on DEB or /etc/sysconfig/kubelet on RPM) is an officially
supported override and has the highest priority among argument sources, while
still clarifying that setting an unrelated env var like KUBELET_LOG_LEVEL will
not affect kubelet args unless placed into one of those expanded variables.
- Line 35: The sed command in the diff (the expression matching
's/^\s*verbosity:.*/verbosity: 4/') writes a top-level verbosity key, but
kubelet expects logging.verbosity; update the fix to set logging.verbosity
instead of a top-level field. Replace the current sed with logic that updates or
creates the nested logging: block and its verbosity: entry (for example, use yq
to set '.logging.verbosity = 4' or with sed/awk ensure a logging: block exists
and then set/append '  verbosity: 4'); ensure you update the exact command that
currently matches '^\s*verbosity:' so it targets 'logging.verbosity' (or
manipulates the logging: section) rather than adding a top-level verbosity key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: abb33d3c-de7e-4afe-aec4-d7b997619f94

📥 Commits

Reviewing files that changed from the base of the PR and between 7a0b251 and 7efbdfb.

📒 Files selected for processing (1)
  • docs/en/solutions/Configure_Kubelet_Log_Level_Verbosity.md


```bash
# On the target node
sudo sed -i 's/^\s*verbosity:.*/verbosity: 4/; t; $a\verbosity: 4' /var/lib/kubelet/config.yaml
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify actual key path used by kubelet config on a node
sudo grep -nE '^\s*logging:|^\s*verbosity:' /var/lib/kubelet/config.yaml

Repository: alauda/knowledge

Length of output: 104


🏁 Script executed:

# Search for kubelet config examples or references in the repository
rg -i 'kubelet.*config|logging\.verbosity|verbosity' docs/ --type md -A 2 -B 2

Repository: alauda/knowledge

Length of output: 11838


🏁 Script executed:

# Check if there are any existing kubelet configuration examples in the repo
fd -e yaml -e json -e md | xargs rg -l 'kubelet' | head -20

Repository: alauda/knowledge

Length of output: 400


🌐 Web query:

Kubernetes kubelet configuration verbosity field path schema logging.verbosity

💡 Result:

The Kubernetes kubelet configuration includes a logging.verbosity field in the KubeletConfiguration struct (v1beta1 API). This field is nested under the top-level logging object and specifies the log verbosity threshold as an integer (VerbosityLevel, alias of uint32). Default is 0 (only most important messages); higher values (e.g., 2-4 for debug, 5-8 for trace) enable more detailed logging. Error messages are always logged. Full path in YAML/JSON config: logging.verbosity Example from official docs: logging: format: "text" flushFrequency: "5s" verbosity: 3 options: json: infoBufferSize: "0" Schema details: - Type: VerbosityLevel (uint32) - Description: Threshold for log messages; higher values log more details. - Appears in: LoggingConfiguration within KubeletConfiguration. Configure via --config flag pointing to a YAML/JSON file matching this schema. Command-line --v flag is deprecated in favor of config file for this parameter.

Citations:


verbosity field path does not match KubeletConfiguration schema.

Per the official Kubernetes kubelet config schema (v1beta1), verbosity is nested under logging.verbosity, not a top-level verbosity field. The sed command will create a top-level field that kubelet ignores, causing the configuration to silently fail.

Suggested fix
- sudo sed -i 's/^\s*verbosity:.*/verbosity: 4/; t; $a\verbosity: 4' /var/lib/kubelet/config.yaml
+ sudo yq -i '.logging.verbosity = 4' /var/lib/kubelet/config.yaml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sudo sed -i 's/^\s*verbosity:.*/verbosity: 4/; t; $a\verbosity: 4' /var/lib/kubelet/config.yaml
sudo yq -i '.logging.verbosity = 4' /var/lib/kubelet/config.yaml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/en/solutions/Configure_Kubelet_Log_Level_Verbosity.md` at line 35, The
sed command in the diff (the expression matching 's/^\s*verbosity:.*/verbosity:
4/') writes a top-level verbosity key, but kubelet expects logging.verbosity;
update the fix to set logging.verbosity instead of a top-level field. Replace
the current sed with logic that updates or creates the nested logging: block and
its verbosity: entry (for example, use yq to set '.logging.verbosity = 4' or
with sed/awk ensure a logging: block exists and then set/append '  verbosity:
4'); ensure you update the exact command that currently matches '^\s*verbosity:'
so it targets 'logging.verbosity' (or manipulates the logging: section) rather
than adding a top-level verbosity key.


### Persistent Configuration — systemd drop-in (fallback)

If you cannot edit `config.yaml` (some operator-managed setups lock the file), override the kubelet `ExecStart` via a drop-in that **inlines the `--v` flag directly**. Setting a bare environment variable like `KUBELET_LOG_LEVEL=4` does **not** raise verbosity — the stock kubeadm systemd unit only expands the three specific variables `$KUBELET_KUBECONFIG_ARGS`, `$KUBELET_CONFIG_ARGS`, and `$KUBELET_KUBEADM_ARGS`; any other name (including `KUBELET_LOG_LEVEL` or `KUBELET_EXTRA_ARGS`) is silently ignored.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect real kubelet unit/env expansion on target nodes
systemctl cat kubelet | sed -n '/^\[Service\]/,/^\[/p'
systemctl show kubelet -p FragmentPath -p DropInPaths -p EnvironmentFiles

Repository: alauda/knowledge

Length of output: 157


🏁 Script executed:

# Search the repository for references to kubelet systemd units, KUBELET_EXTRA_ARGS, or ExecStart
rg -i "kubelet.*extra.*args|KUBELET_EXTRA_ARGS|ExecStart.*kubelet" --type md --type txt --type yaml --type json

Repository: alauda/knowledge

Length of output: 1200


🏁 Script executed:

# Look for any kubeadm or kubelet configuration files in the repository
fd -i "kubelet|kubeadm" -type f | head -20

Repository: alauda/knowledge

Length of output: 230


🌐 Web query:

kubeadm systemd unit template kubelet environment variables KUBELET_EXTRA_ARGS official documentation

💡 Result:

The official Kubernetes documentation describes the kubeadm systemd unit template for the kubelet in the page "Configuring each kubelet in your cluster using kubeadm" at https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/kubelet-integration/. The key drop-in file is /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf, which augments the base kubelet.service. It sources environment variables including KUBELET_EXTRA_ARGS from /etc/default/kubelet (DEB packages) or /etc/sysconfig/kubelet (RPM packages). Here is the template content from the official docs: [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generate at runtime, populating # the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, # the user should use the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. # KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/default/kubelet ExecStart= ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS To use KUBELET_EXTRA_ARGS, add it to /etc/default/kubelet (or /etc/sysconfig/kubelet on RPM), e.g.: KUBELET_EXTRA_ARGS="--fail-swap-on=false --max-pods=110" Then run systemctl daemon-reload && systemctl restart kubelet. This has highest priority among the arg sources. Prefer NodeRegistration.KubeletExtraArgs in kubeadm config files instead.

Citations:


Correct the claim about expanded variables in kubeadm systemd units.

The official Kubernetes documentation shows that the stock kubeadm systemd unit template DOES expand $KUBELET_EXTRA_ARGS in the ExecStart line. The template sources this from /etc/default/kubelet (DEB) or /etc/sysconfig/kubelet (RPM). Saying that KUBELET_EXTRA_ARGS is "silently ignored" is factually incorrect — it is an officially supported mechanism with the highest priority among argument sources. The documentation should specify all four expanded variables ($KUBELET_KUBECONFIG_ARGS, $KUBELET_CONFIG_ARGS, $KUBELET_KUBEADM_ARGS, and $KUBELET_EXTRA_ARGS) rather than claiming only three are supported.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/en/solutions/Configure_Kubelet_Log_Level_Verbosity.md` at line 43,
Update the paragraph to correct the factual error: state that the kubeadm
systemd unit template expands four variables in ExecStart —
$KUBELET_KUBECONFIG_ARGS, $KUBELET_CONFIG_ARGS, $KUBELET_KUBEADM_ARGS, and
$KUBELET_EXTRA_ARGS — and remove the claim that KUBELET_EXTRA_ARGS is "silently
ignored"; instead note that KUBELET_EXTRA_ARGS (sourced from
/etc/default/kubelet on DEB or /etc/sysconfig/kubelet on RPM) is an officially
supported override and has the highest priority among argument sources, while
still clarifying that setting an unrelated env var like KUBELET_LOG_LEVEL will
not affect kubelet args unless placed into one of those expanded variables.

Comment on lines +126 to +128
for n in $(kubectl get nodes --no-headers | awk '{print $1}'); do
ssh "$n" "sudo journalctl -u kubelet.service --since '1 hour ago'" > "${n}.kubelet.log"
done
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Using Kubernetes node name as SSH host is brittle.

ssh "$n" often fails because node name is not guaranteed to be DNS-resolvable/reachable from the runner host.

Portable alternative using InternalIP
-for n in $(kubectl get nodes --no-headers | awk '{print $1}'); do
-  ssh "$n" "sudo journalctl -u kubelet.service --since '1 hour ago'" > "${n}.kubelet.log"
+kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{range .status.addresses[*]}{.type}={.address}{" "}{end}{"\n"}{end}' \
+| while read -r name addrs; do
+  ip=$(printf '%s\n' "$addrs" | tr ' ' '\n' | awk -F= '$1=="InternalIP"{print $2; exit}')
+  [ -n "$ip" ] && ssh "$ip" "sudo journalctl -u kubelet.service --since '1 hour ago'" > "${name}.kubelet.log"
 done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for n in $(kubectl get nodes --no-headers | awk '{print $1}'); do
ssh "$n" "sudo journalctl -u kubelet.service --since '1 hour ago'" > "${n}.kubelet.log"
done
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{range .status.addresses[*]}{.type}={.address}{" "}{end}{"\n"}{end}' \
| while read -r name addrs; do
ip=$(printf '%s\n' "$addrs" | tr ' ' '\n' | awk -F= '$1=="InternalIP"{print $2; exit}')
[ -n "$ip" ] && ssh "$ip" "sudo journalctl -u kubelet.service --since '1 hour ago'" > "${name}.kubelet.log"
done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/en/solutions/Configure_Kubelet_Log_Level_Verbosity.md` around lines 126
- 128, The loop uses node names (variable n and ssh "$n") which may not be
DNS-resolvable; change the selection to use each node's InternalIP and keep the
node name for filenames: iterate over pairs (node name and InternalIP) by
replacing the kubectl invocation with a jsonpath or custom-columns query (e.g.,
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}
{.status.addresses[?(@.type=="InternalIP")].address}{"\n"}{end}' or equivalent),
then in the loop use ssh "$IP" to run sudo journalctl -u kubelet.service --since
'1 hour ago' and redirect to "${NODE}.kubelet.log" so SSH targets the reachable
IP while filenames still use the node name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant